import matplotlib.pyplot as plt
from pathlib import (
    Path,
)


class PlotConfig:
    """
    配置绘图样式和路径的类。
    """

    def __init__(
            self,
    ) -> None:
        """
        初始化 PlotConfig 实例，设置绘图的字体大小、线条宽度、颜色等参数，并创建必要的文件夹。
        """
        self._pre_init()

        # 设置图形宽度（以英寸为单位）
        self.textwidth = 3.50  # IEEE 双栏：3.5，论文：5.81

        # 设置字体大小
        plt.rc('axes', labelsize=8.33)  # 轴标签的字体大小，单位为磅（pt），默认为 10
        plt.rc('xtick', labelsize=8.33)  # x 轴刻度标签的字体大小，单位为磅（pt），默认为 10
        plt.rc('ytick', labelsize=8.33)  # y 轴刻度标签的字体大小，单位为磅（pt），默认为 10
        plt.rc('legend', fontsize=6.67)  # 图例的字体大小，单位为磅（pt），默认为 10

        # 设置线条宽度和标记大小
        plt.rc('lines', linewidth=1)  # 线条宽度
        plt.rc('lines', markersize=4)  # 标记的大小
        plt.rc('errorbar', capsize=3)  # 误差条的帽子大小

        # 设置网格线样式
        plt.rc(
            'grid',
            color='gainsboro',  # 网格线颜色
            linewidth=0.5 * plt.rcParams['grid.linewidth']  # 网格线宽度，默认为 0.8
        )
        plt.rc('axes.spines', top=False, right=False)  # 隐藏坐标轴上边框和右边框
        plt.rc('xtick.minor', visible=True)  # 显示 x 轴次刻度
        plt.rc('ytick.minor', visible=True)  # 显示 y 轴次刻度
        plt.rc('font', family='serif')  # 标签字体系列，['serif', 'sans-serif', 'monospace']

        # 使用 LaTeX 渲染文本
        plt.rc('text', usetex=True)  # 在刻度上使用 LaTeX 数学公式，默认值为 False

    def _pre_init(
            self,
    ) -> None:
        """
        在初始化时设置路径和颜色调色板。
        """
        # 设置路径
        self.project_root_path = Path(__file__).parent.parent.parent  # 项目根路径
        self.plots_parent_path = Path(self.project_root_path, 'reports', 'figures')  # 绘图保存路径

        # 创建保存路径的文件夹（如果不存在）
        self.plots_parent_path.mkdir(parents=True, exist_ok=True)

        # 颜色调色板（色盲调色板）
        self.cp2: dict[str: str] = {
            'magenta': '#d01b88',
            'blue': '#254796',
            'green': '#307b3b',
            'gold': '#caa023',
            'white': '#ffffff',
            'black': '#000000',
        }

        # 颜色调色板（大学品牌色）
        self.cp3: dict[str: str] = {
            'red1': '#9d2246',
            'red2': '#d50c2f',
            'red3': '#f39ca9',
            'blue1': '#00326d',
            'blue2': '#0068b4',
            'blue3': '#89b4e1',
            'purple1': '#3b296a',
            'purple2': '#8681b1',
            'purple3': '#c7c1e1',
            'peach1': '#d45b65',
            'peach2': '#f4a198',
            'peach3': '#fbdad2',
            'orange1': '#f7a600',
            'orange2': '#fece43',
            'orange3': '#ffe7b6',
            'green1': '#008878',
            'green2': '#8acbb7',
            'green3': '#d6ebe1',
            'yellow1': '#dedc00',
            'yellow2': '#f6e945',
            'yellow3': '#fff8bd',
            'white': '#ffffff',
            'black': '#000000',
        }

        # 颜色调色板（冰淇淋柔和色调）
        self.cp4 = {
            'brown': '#D3BBA7',
            'grey': '#C5CDD3',
            'red': '#ECC0C1',
            'orange': '#FFDCCC',
            'vanilla': '#FFF9EC',
            'mint': '#d8e2dc',
            'blue': '#C6DEF1',
            'white': '#ffffff',
            'black': '#000000',
        }

        # 颜色调色板（彩虹柔和色调）
        self.cp5 = {
            'brown': '#E2CFC4',
            'orange': '#F7D9C4',
            'yellow': '#FAEDCB',
            'green': '#C9E4DE',
            'blue': '#C6DEF1',
            'purple': '#DBCDF0',
            'pink': '#F2C6DE',
            'red': '#F9C6C9',
            'light_grey': '#E2E2DF',
            'dark_grey': '#D2D2CF',
            'white': '#ffffff',
            'black': '#000000',
        }


def save_figures(
        plots_parent_path,
        plot_name,
        padding,
) -> None:
    """
    保存图形为不同格式的文件。
    
    参数:
        plots_parent_path (Path): 图形保存路径
        plot_name (str): 图形文件名
        padding (float): 图形边缘的填充
    """
    plt.savefig(Path(plots_parent_path, 'pgf', f'{plot_name}.pgf'),
                bbox_inches='tight', pad_inches=padding, transparent=True)
    plt.savefig(Path(plots_parent_path, 'pdf', f'{plot_name}.pdf'),
                bbox_inches='tight', pad_inches=padding, dpi=800, transparent=True)
    plt.savefig(Path(plots_parent_path, 'eps', f'{plot_name}.eps'),
                bbox_inches='tight', pad_inches=padding)


def generic_styling(
        ax,
) -> None:
    """
    为图形的坐标轴应用通用样式。

    参数:
        ax (matplotlib.axes.Axes): 要应用样式的坐标轴对象
    """
    ax.set_axisbelow(True)  # 确保网格线位于图形的下方
    ax.grid()  # 显示网格线
    ax.grid(
        which='minor',
        color='whitesmoke',
        linewidth=0.8 * plt.rcParams['grid.linewidth']  # 设置次刻度网格线的宽度
    )
    ax.tick_params(axis='y', which='minor', left=False)  # 隐藏 y 轴的次刻度刻度线


def pt_to_inches(
        pt: float
) -> float:
    """
    将点数（pt）转换为英寸。

    参数:
        pt (float): 点数

    返回:
        float: 英寸数
    """
    return 0.01389 * pt


def plot_color_palette(
        color_palette: dict
) -> None:
    """
    绘制颜色调色板。

    参数:
        color_palette (dict): 颜色调色板字典
    """
    list_of_colors = list(color_palette.keys())  # 获取颜色名称列表

    plt.figure()
    for ii in range(len(list_of_colors)):
        plt.barh(ii, 10, color=color_palette[list_of_colors[ii]])  # 绘制颜色条

    plt.yticks(range(len(list_of_colors)), list_of_colors)  # 设置 y 轴刻度标签为颜色名称
    plt.grid(alpha=.25)  # 显示网格线
    plt.show()  # 显示图形
